import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.Timer;


public class MapDrawer extends JFrame implements MouseListener, KeyListener {

	private static final long serialVersionUID = 1L;
	
	private Map map;
	private Point clickedGrid = new Point();
	private Timer timer;

	public int xGrids;
	public int yGrids;
	
	public static final int gridSize = 30;
	public static final int offset = 20;
	public static final int titleBarSize = 20;


	public MapDrawer(Map map) {
		xGrids = map.xGrids;
		yGrids = map.yGrids;

		setSize(offset + xGrids * gridSize + offset, offset + yGrids * gridSize + offset + titleBarSize);
		setLocation(100, 100);
		//setUndecorated(true);
		setVisible(true);

		getContentPane().addMouseListener(this);
		addKeyListener(this);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.map = map;
		
		timer = new Timer(100, new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				repaint();
			}
		});
		timer.start();
	}

	public void paint(Graphics g) {
		Graphics2D g2 = (Graphics2D) g;
		g2.setPaint(Color.white);
		g2.clearRect(0, 0, offset + yGrids * gridSize + offset, offset + xGrids * gridSize + offset);

		drawGrids(g2);
		drawRuler(g2);
		drawBoundary(g2);
		drawObstacles(g2);
		drawRobot(g2);
	}

	public void drawGrids(Graphics2D g2) {
		for(int i = 0; i < xGrids; i++) {
			for(int j = 0; j < yGrids; j++) {
				g2.setPaint(Color.white);

				if(map.grids[i][j].color == Constants.FIRST_ROOM)
					g2.setPaint(Color.green);
				else if(map.grids[i][j].color == Constants.SECOND_ROOM)
					g2.setPaint(Color.red);
				else if(map.grids[i][j].color == Constants.KING)
					g2.setPaint(Color.yellow);
				else if(map.grids[i][j].seen>0)
					g2.setPaint(Color.pink);
				
				if(map.grids[i][j].closed)
					g2.setPaint(Color.black);

				g2.fillRect(offset + i * gridSize, offset + titleBarSize + j * gridSize, gridSize, gridSize);
			}
		}
	}

	public void drawRuler(Graphics2D g2) {
		g2.setPaint(Color.lightGray);
		for(int i = 0; i < map.verticalObstacles.length; i++) {
			g2.drawLine(offset + (i + 1) * gridSize, offset + titleBarSize, offset + (i + 1) * gridSize, offset + titleBarSize + yGrids * gridSize);
		}
		for(int i = 0; i < map.horizontalObstacles.length; i++) {
			g2.drawLine(offset, offset + titleBarSize + (i + 1) * gridSize, offset + xGrids * gridSize, offset + titleBarSize + (i + 1) * gridSize);
		}
	}

	public void drawBoundary(Graphics2D g2){
		g2.setPaint(Color.orange);
		g2.setStroke(new BasicStroke(1));

		g2.drawLine(offset, offset + titleBarSize , offset, offset + titleBarSize + yGrids * gridSize);
		g2.drawLine(offset, offset + titleBarSize , offset + xGrids * gridSize, offset + titleBarSize);
		g2.drawLine(offset, offset + titleBarSize  + yGrids * gridSize, offset + xGrids * gridSize, offset + titleBarSize + yGrids * gridSize);
		g2.drawLine(offset + xGrids * gridSize, offset + titleBarSize , offset + xGrids * gridSize, offset + titleBarSize + yGrids * gridSize);
	}

	public void drawObstacles(Graphics2D g2){
		g2.setPaint(Color.black);
		g2.setStroke(new BasicStroke(1));

		for(int i = 0; i < map.verticalObstacles.length; i++) {
			for(int j = 0; j < map.verticalObstacles[0].length; j++) {
				if(map.verticalObstacles[i][j].exists)
					g2.drawLine(offset + (i + 1) * gridSize, offset + titleBarSize + j * gridSize, offset + (i + 1) * gridSize, offset + titleBarSize + (j + 1) * gridSize);
			}
		}

		for(int i = 0; i < map.horizontalObstacles.length; i++) {
			for(int j = 0; j < map.horizontalObstacles[0].length; j++) {
				if(map.horizontalObstacles[i][j].exists)
					g2.drawLine(offset + i * gridSize, offset + titleBarSize + (j + 1) * gridSize, offset + (i + 1) * gridSize, offset + titleBarSize + (j + 1) * gridSize);
			}
		}
	}

	public void drawRobot(Graphics2D g2){
		g2.setPaint(Color.blue);
		g2.drawOval(offset + Robot.x * gridSize + gridSize / 2, offset + titleBarSize + Robot.y * gridSize + gridSize / 2, 5, 5);
	}

	////////////MOUSE LISTENER/////////////////
	@Override
	public void mouseClicked(MouseEvent e) {
		int x = e.getX() - offset;
		int y = e.getY() - offset;

		if(x <= 0 || x >= xGrids * gridSize || y <= 0 || y >= yGrids * gridSize)
			return;

		x = x / gridSize;
		y = y / gridSize;

		clickedGrid.setLocation(x, y);
	}

	@Override
	public void mousePressed(MouseEvent e) {}
	@Override
	public void mouseReleased(MouseEvent e) {}
	@Override
	public void mouseEntered(MouseEvent e) {}
	@Override
	public void mouseExited(MouseEvent e) {}



	///////////////KEYBOARD LISTENER////////////////

	@Override
	public void keyPressed(KeyEvent e) {
		
		if(e.getKeyCode() == KeyEvent.VK_K) {
			Simulator.instance.start();
		}
		else if(e.getKeyCode() == KeyEvent.VK_P) {
			repaint();
		}
		else if(e.getKeyCode() == KeyEvent.VK_UP) {
			if(clickedGrid.y == 0)
				return;
			map.setObstacle(clickedGrid.x, clickedGrid.y - 1, !map.horizontalObstacles[clickedGrid.x][clickedGrid.y - 1].exists, false);
		}
		else if(e.getKeyCode() == KeyEvent.VK_DOWN) {
			if(clickedGrid.y == yGrids - 1)
				return;
			map.setObstacle(clickedGrid.x, clickedGrid.y, !map.horizontalObstacles[clickedGrid.x][clickedGrid.y].exists, false);
		}
		else if(e.getKeyCode() == KeyEvent.VK_LEFT) {
			if(clickedGrid.x == 0)
				return;
			map.setObstacle(clickedGrid.x - 1, clickedGrid.y, !map.verticalObstacles[clickedGrid.x - 1][clickedGrid.y].exists, true);
		}
		else if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
			if(clickedGrid.x == xGrids - 1)
				return;
			map.setObstacle(clickedGrid.x, clickedGrid.y, !map.verticalObstacles[clickedGrid.x][clickedGrid.y].exists, true);
		}
		else if(e.getKeyCode() == KeyEvent.VK_Q) {
			map.grids[clickedGrid.x][clickedGrid.y].color = Constants.EMPTY;
		}
		else if(e.getKeyCode() == KeyEvent.VK_W) {
			map.grids[clickedGrid.x][clickedGrid.y].color = Constants.FIRST_ROOM;
		}
		else if(e.getKeyCode() == KeyEvent.VK_E) {
			map.grids[clickedGrid.x][clickedGrid.y].color = Constants.SECOND_ROOM;
		}
		else if(e.getKeyCode() == KeyEvent.VK_R) {
			map.grids[clickedGrid.x][clickedGrid.y].color = Constants.KING;
		}

		repaint();
	}

	@Override
	public void keyReleased(KeyEvent e) {}
	@Override
	public void keyTyped(KeyEvent e) {}
}
